package TestCases;
import java.io.File;
import java.util.ArrayList;
import java.util.Map;
import java.util.Set;

import junit.framework.TestCase;

import Parser.Lexer;
import Parser.Parser;
import Parser.Rule;
import Parser.Run;

/* TODO Perhaps we should group these methods by class
 * 		and alphabetical order so that they are 
 *		more organized?
 * 
 */

public class RunLexerParserTests extends TestCase  {
	
	
	//****************** LEXER TESTS **************************//
	
	public void testLexer() {
		Run run = new Run();
		File parseFile = new File("correct.txt");
		File grammarFile = new File("tinyGrammar.txt");
		run.load(grammarFile);
		
		Lexer lexer = new Lexer(parseFile, run.getTokenList());
		String list = "";
		lexer.retrieveTokens();
		String tester = "";
		if(lexer.getTokens() == null) { fail("Lexer found grammar to be incorrect"); }
		for (String e: lexer.getTokens()) tester += e + " ";
		System.out.println(tester);
		assertEquals(tester, "LEFTPAR INTNUM PLUS BEGIN INTNUM ASSIGN MULTIPLY ID ID RIGHTPAR ");
	}
	
	public void testLexer2() {
		boolean found = false;
		Run run = new Run();
		File parseFile = new File("wrong.txt");
		File grammarFile = new File("tinyGrammar.txt");
		run.load(grammarFile);
		
		Lexer lexer = new Lexer(parseFile, run.getTokenList());
		String list = "";
		lexer.retrieveTokens();
		assertTrue(lexer.getTokens() == null);
	}
	
	//Test using the example the TA posted in the project clarification sheet
	public void testLexerProjectClarification() {
		Run run = new Run();
		File parseFile = new File("projectClarificationInput");
		File grammarFile = new File("tinyGrammar.txt");
		run.load(grammarFile);
		
		Lexer lexer = new Lexer(parseFile, run.getTokenList());
		String list = "";
		lexer.retrieveTokens();
		String tester = "";
		for (String e: lexer.getTokens()) tester += e + " ";
		System.out.println(tester);
		assertEquals(tester, "LEFTPAR ID COMMA LEFTPAR ID RIGHTPAR COMMA INTNUM RIGHTPAR ");
	}
	
	
	//**************************** PARSER TESTS ************************//
	
	/** 
	 * It got this case correct.
	 */
	public void testGetFirstSet() {
		Run run = new Run();
		Parser parse = new Parser();
		run.load(new File("firstSetSampleGrammar.txt"));
		ArrayList<Rule> rulesList = run.getRulesList();
		String header = String.format("%n%s", "testGetFirstSet:");
		System.out.println(header);
		Map<String, Set<String>> tryFirstSet = parse.getFirstSet(rulesList);
		Parser.printSet(tryFirstSet);
	}
		
	/**
	 * If we follow the algorithm in the slides,
	 * then this produces the correct output, but
	 * something seems off.
	 */
	public void testGetFollowSet() {
		Run run = new Run();
		Parser parse = new Parser();
		run.load(new File("firstSetSampleGrammar.txt"));
		ArrayList<Rule> rulesList = run.getRulesList();
		String header = String.format("%n%s", "testGetFollowSet:");
		System.out.println(header);
		Map<String, Set<String>> tryFirstSet = parse.getFollowSet(rulesList, run.getStart());
		Parser.printSet(tryFirstSet);
	}
	
	/**
	 * Running through the example we did in class to ensure that the first sets, 
	 * follow sets and parseTable values match what was in the class slides
	 */
	public void testClassRoomExample() {
		Run run = new Run();
		Parser parse = new Parser();
		run.load(new File("classSlidesExample.txt"));
		ArrayList<Rule> rulesList = run.getRulesList();
		System.out.println("\n *** TEST CLASSROOM EXAMPLE: *** \n");
		System.out.println("*** FIRST SET ***");
		Map<String, Set<String>> tryFirstSet = parse.getFirstSet(rulesList);
		Parser.printSet(tryFirstSet);
		
		System.out.println("\n *** FOLLOW SET ***");
		Map<String, Set<String>> tryFollowSet = parse.getFollowSet(rulesList, run.getStart());
		Parser.printSet(tryFollowSet);
		
		System.out.println("\n *** PARSE TABLE ***");
		Map<String, Rule> parseTable = parse.getParseTable(tryFirstSet, tryFollowSet, rulesList);
		parse.printTable(parseTable);
		
		System.out.println("\n *** PARSING ALGORITHM ***");
		Lexer lexer = new Lexer(new File("classInput.txt"), run.getTokenList());
		lexer.retrieveTokens();
		parse.parse(parseTable, lexer.getTokens(), run.getStart());
	}
	
	/**
	 * Running through an example posted in the project clarification pdf
	 */
	public void testProjectClarification() {
		Run run = new Run();
		Parser parse = new Parser();
		run.load(new File("projectClarificationExample.txt"));
		ArrayList<Rule> rulesList = run.getRulesList();
		System.out.println("\n *** TEST PROJECT CLARIFICATION SHEET: *** \n");
		System.out.println("*** FIRST SET ***");
		Map<String, Set<String>> tryFirstSet = parse.getFirstSet(rulesList);
		Parser.printSet(tryFirstSet);
		
		System.out.println("\n *** FOLLOW SET ***");
		Map<String, Set<String>> tryFollowSet = parse.getFollowSet(rulesList, run.getStart());
		Parser.printSet(tryFollowSet);
		
		System.out.println("\n *** PARSE TABLE ***");
		Map<String, Rule> parseTable = parse.getParseTable(tryFirstSet, tryFollowSet, rulesList);
		parse.printTable(parseTable);
		
		System.out.println("\n *** PARSING ALGORITHM ***");
		Lexer lexer = new Lexer(new File("projectClarificationInput"), run.getTokenList());
		lexer.retrieveTokens();
		parse.parse(parseTable, lexer.getTokens(), run.getStart());
	}
	
	//****************** RULE TESTS **********************************//
	
	public void testIsNonTerminal() {
		Run run = new Run();
		run.load(new File("tinyGrammar.txt"));
		for(Rule rule : run.getRulesList()) {
			assertTrue(rule.isNonTerminal(rule.getTitle()));
		}
		assertFalse(new Rule ().isNonTerminal("<>"));
	}
	
	
	//********************** RUN TESTS ***************************//
	
	public void testLeftRecursion() {
		Run run = new Run();
		run.load(new File("tinyGrammar.txt"));
		for (Rule e: run.getRulesList()) System.out.println(e);
	}
	
	public void testLeftFactor() {
		Run run = new Run();
		run.load(new File("tinyGrammarWithCommonFactors.txt"));
		run.leftFactor();
		String test = "";
		for (Rule e: run.getRulesList()) test += e;
		String a = "<A> : <u> <A'>";
		String b = "<A'> : <v>";
		String c = "<A'> : <w>";
		
		for (Rule e: run.getRulesList()) System.out.println(e);
		assertTrue(test.contains(a));
		assertTrue(test.contains(b));
		assertTrue(test.contains(c));
	}
}
